---计划者，负责根据目标及代理拥有的动作，制定计划
---@class Planner
---@field agent AgentBase
Planner = class()

function Planner:ctor(agent)
    self.agent = agent;
end

---构建计划
---@param goal GoalBase
function Planner:BuildPlan(goal)
    Debug.Log("制定计划");
    Debug.Log("---------当前代理状态---------");
    Debug.Log(self.agent.agentState:ToString());
    Debug.Log("--------当前代理状态End--------");
    local plan = Queue.new();
    if goal == nil then
        return plan
    end
    local currentNode = self:Plan(goal);
    if currentNode == nil then
        plan:Enqueue(self.agent.actionManager:GetHandler(self.agent.actionManager:GetDefaultActionLabel()));
        Debug.LogError("当前节点为空，设置当前动作为默认动作");
        return plan;
    end
    while (currentNode.ID ~= GOAPTreeNode.DEFAULT_ID) do
        plan:Enqueue(currentNode.actionHandler);
        currentNode = currentNode.parentNode;
    end

    return plan;
end

---生成计划树
---@param goal GoalBase
function Planner:Plan(goal)
    ---@type GOAPTreeNode
    local topNode = self:CreateTopNode(goal);
    ---@type GOAPTreeNode
    local cheapestNode = nil;
    ---@type GOAPTreeNode
    local currentNode = topNode;
    ---@type GOAPTreeNode
    local subNode = nil;

    while (not self:IsEnd(currentNode)) do
        local handlers = self:GetSubHandlers(currentNode);
        Debug.Log("----currentNode:"..currentNode.ID.."----");
        for i, v in ipairs(handlers) do
            Debug.Log("计划子行为："..v.label.."  优先级："..v.action.priority);
        end
        Debug.Log("------currentNode End------")

        for i, v in ipairs(handlers) do
            subNode = GOAPTree:CreateNode(v);
            self:SetNodeState(currentNode,subNode);
            subNode.cost = self:GetCost(subNode);
            subNode.parentNode = currentNode;
            cheapestNode = self:GetCheapestNode(subNode,cheapestNode);
        end
        currentNode = cheapestNode;
        cheapestNode = nil;
    end
    return currentNode;
end

---创建头结点
---@param goal GoalBase
function Planner:CreateTopNode(goal)
    local topNode = GOAPTree:CreateTopNode();
    topNode.goalState:SetByOther(goal:GetEffects());
    topNode.cost = self:GetCost(topNode);
    self:SetNodeCurrentState(topNode);
    return topNode;
end

---获取节点花费
---@param node GOAPTreeNode
function Planner:GetCost(node)
    local actionCost = 0;
    if node.actionHandler ~= nil then
        actionCost = node.actionHandler.action.cost;
    end
    return node.cost + actionCost + self:GetStateDifferecnceNum(node);
end

---@param currentNode GOAPTreeNode
---@param subNode GOAPTreeNode
function Planner:SetNodeState(currentNode,subNode)
    if subNode.ID < GOAPTreeNode.DEFAULT_ID then
        return;
    end
    local subAction = subNode.actionHandler.action;
    ---首先复制当前节点的状态
    subNode:CopyState(currentNode);
    ---查找action的effects,和goal中也存在
    local data = subNode.goalState:GetSameKeyData(subAction.effects);
    ---那么就把这个状态添加到节点的当前状态中
    subNode.currentState:SetByOther(data);
    ---把action的先决条件存在goalState中不存在的简直添加进去
    for k, v in pairs(subAction.preconditions.dataTable) do
        if not subNode.goalState:ContainKey(k) then
            subNode.goalState:Set(k,subAction.preconditions:Get(k));
        end
    end
    self:SetNodeCurrentState(subNode);
end

---设置当前节点的状态
---@param node GOAPTreeNode
function Planner:SetNodeCurrentState(node)
    ---把GoalState中有且CurrentState没有的添加到CurrentState中
    ---数据从agent的当前状态中获取
    local keys = node.currentState:GetNotExistKeys(node.goalState);
    for i, v in ipairs(keys) do
        node.currentState:Set(v,self.agent.agentState:Get(v));
    end
end

---是否已经是最后节点
---@param currentNode GOAPTreeNode
function Planner:IsEnd(currentNode)
    if currentNode == nil then
        return true;
    end
    if self:GetStateDifferecnceNum(currentNode) == 0 then
        return true;
    end
    return false;
end

---获取与目标节点状态不同的数量
---@param node GOAPTreeNode
function Planner:GetStateDifferecnceNum(node)
    return table.count(node.currentState:GetValueDifferences(node.goalState));
end

---获取所有的子节点动作
---@param node GOAPTreeNode
---@return ActionHandlerBase[]
function Planner:GetSubHandlers(node)
    local handlers = {}
    if node == nil then
        return handlers;
    end

    ---获取状态差异
    local keys = node.currentState:GetValueDifferences(node.goalState);
    local map = self.agent.actionManager.effectsAndActionMap;
    for i, v in ipairs(keys) do
        if map[v] ~= nil then
            for m, n in pairs(map[v]) do
                ---@type ActionHandlerBase
                local handler = n;
                ---筛选能够执行的动作
                if table.indexOf(handlers,handler) == -1 and handler.action.effects:Get(v) == node.goalState:Get(v) then
                    table.insert(handlers,handler);
                end
            end
        else
            Debug.LogError("当前没有动作能够实现从当前状态切换到目标状态，无法实现的键值为："..v);
        end
    end
    ---进行优先级排序
    table.sort(handlers,function (a,b)
        local a = a;
        local b = b;
        return a.action.priority > b.action.priority;
    end)
    return handlers;
end

---获取最便宜的节点
---@param nodeA GOAPTreeNode
---@param nodeB GOAPTreeNode
function Planner:GetCheapestNode(nodeA,nodeB)
    if nodeA == nil or nodeA.actionHandler == nil then
        return nodeB;
    end
    if nodeB == nil or nodeB.actionHandler == nil then
        return nodeA;
    end
    if nodeA.cost > nodeB.cost then
        return nodeB;
    elseif nodeA.cost < nodeB.cost then
        return nodeA;
    else
        if nodeA.actionHandler.action.priority > nodeB.actionHandler.action.priority then
            return nodeA;
        else
            return nodeB;
        end
    end
end